package cn.fulong.frame.service.impl;

import cn.fulong.frame.service.GetData;
import cn.fulong.frame.service.NativeSqlUtil;
import cn.fulong.frame.utils.DateTimeUtil;
import cn.fulong.frame.view.Pagination;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.BeanWrapperImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpSession;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Service("getDataFromSQL")
public class GetDataFromSQL extends GetData {
    @Value("${application.limited-max-rows:5000}")
    private Integer maxRow;
    @Autowired
    private HttpSession session;
    @Autowired
    private JdbcTemplate jdbcTemplate;

    @Override
    public Map execute(Map dataset, Map args) throws Exception {
        String sql = getStringFromDataset(dataset, "sql");
        if (StringUtils.isBlank(sql)) {
            return null;
        }

        // 拼装sql
        sql = assemble(sql, dataset, args);

        // 处理session参数
        //sql = dealSession(sql);
        // 改为处理用户参数 2020-8-20
        sql = dealUserArgs(sql, args);
        if (StringUtils.isBlank(sql)) {
            return null;
        }

        // 处理redis参数 调用服务的结果
        sql = dealCache(sql);
        System.out.println(sql);

        // 参数子集
        Object[] arguments = subsets(dataset, args);

        int pageSize = getPageSize(dataset, args);
        int pageNo = getPageNo(dataset, args);

        // 根据scope 执行 jdbcTemplate.queryForMap, topSQL, pageSQL, countSQL
        String ds = getStringFromDataset(dataset, "name");
        int dbms = (Integer) dataset.get("dbms");
        List transcodes = getTranscodes(dataset);
        Map result = new HashMap();
        List data;
        int scope = (Integer) dataset.get("scope");
        int count;
        String countSql;
        switch (scope) {
            case 1: //一条
                Map map;
                if (arguments != null && arguments.length > 0) {
                    map = jdbcTemplate.queryForMap(sql, arguments);
                } else {
                    map = jdbcTemplate.queryForMap(sql);
                }
                if (transcodes != null && transcodes.size() > 0) {
                    transcodeMap(transcodes, map);
                }
                result.put(ds, map);
                break;
            case 2: //前几条
                if (pageSize > maxRow) {
                    return null;
                }
                sql = NativeSqlUtil.topSQL(dbms, sql, pageSize);

                if (arguments != null && arguments.length > 0) {
                    data = jdbcTemplate.queryForList(sql, arguments);
                } else {
                    data = jdbcTemplate.queryForList(sql);
                }

                if (transcodes != null && transcodes.size() > 0) {
                    transcodeList(transcodes, data);
                }
                result.put(ds, data);
                break;
            case 3: //分页
                if (pageSize > maxRow) {
                    return null;
                }
                countSql = NativeSqlUtil.countSQL(dbms, sql);
                if (arguments != null && arguments.length > 0) {
                    count = jdbcTemplate.queryForObject(countSql, arguments, Integer.class);
                } else {
                    count = jdbcTemplate.queryForObject(countSql, Integer.class);
                }
                Pagination page = new Pagination(count, pageNo, pageSize);
                result.put(ds + "page", page);

                sql = NativeSqlUtil.pageSQL(dbms, sql, page.getRowFrom(), page.getRowTo());
                if (arguments != null && arguments.length > 0) {
                    data = jdbcTemplate.queryForList(sql, arguments);
                } else {
                    data = jdbcTemplate.queryForList(sql);
                }

                if (transcodes != null && transcodes.size() > 0) {
                    transcodeList(transcodes, data);
                }
                result.put(ds, data);
                break;
            case 4: //全部
                countSql = NativeSqlUtil.countSQL(dbms, sql);
                if (arguments != null && arguments.length > 0) {
                    count = jdbcTemplate.queryForObject(countSql, arguments, Integer.class);
                } else {
                    count = jdbcTemplate.queryForObject(countSql, Integer.class);
                }
                if (count > maxRow) {
                    return null;
                }

                if (arguments != null && arguments.length > 0) {
                    data = jdbcTemplate.queryForList(sql, arguments);
                } else {
                    data = jdbcTemplate.queryForList(sql);
                }

                if (transcodes != null && transcodes.size() > 0) {
                    transcodeList(transcodes, data);
                }
                result.put(ds, data);
        }
        return result;
    }

    /**
     * 替换sql中的session参数: area_id like substring($user.areaId$,1,4)||'%'
     * 从session获取变量user.areaId
     */
    private String dealSession(String sql) {
        if (StringUtils.isBlank(sql)) {
            return "";
        }

        String[] s = sql.split("\\$");
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < s.length; i++) {
            if (i % 2 == 0) {
                sb.append(s[i]);
            } else {
                String[] s2 = s[i].split("\\.");
                if (s2.length == 1) {
                    // 数据是string
                    Object oArg = session.getAttribute(s2[0]);
                    String arg = oArg.toString();
                    sb.append(arg);
                } else {
                    // 数据是对象的属性值
                    Object so = session.getAttribute(s2[0]);
                    if (so == null) {
                        return "";
                    }
                    BeanWrapper bw = new BeanWrapperImpl(so);
                    String arg = String.valueOf(bw.getPropertyValue(s2[1]));
                    sb.append(arg);
                }
            }
        }
        return sb.toString();
    }

    /**
     * 获取参数子集
     *
     * @param args    Map = {key=arg1,value=”abc”; key=arg2,value=123}
     * @param dataset vars List = [“arg1”,”arg2”]
     * @return Object[] arg = {“abc”,123}
     */
    private Object[] subsets(Map dataset, Map args) {
        List<Map> vars = getVars(dataset);
        if (vars == null || vars.size() < 1) {
            return null;
        }

        List<Object> argList = new ArrayList<>();
        for (Map var : vars) {
            String argValue = (String) args.get(var.get("argName"));
            if (!StringUtils.isBlank(argValue)) {
                if ("ignore".equals(var.get("ignore"))) {
                    continue;
                }

                argValue = ((var.get("prefix") == null) ? "" : var.get("prefix").toString()) + argValue
                        + ((var.get("suffix") == null) ? "" : var.get("suffix"));
                // 转时间类型
                if (StringUtils.isNotBlank((String) var.get("dateFormat"))) {
                    argList.add(DateTimeUtil.parseLocalDateTime(argValue, (String) var.get("dateFormat")));
                } else {
                    argList.add(argValue);
                }
                continue;
            }
            //argValue参数值为空
            if ("yes".equals(var.get("ignore"))) {
                continue;
            }
            String defaultValue = (String) var.get("defaultValue");
            if (!StringUtils.isBlank(defaultValue)) {
                argList.add(defaultValue);
            }
        }
        Object[] arg = argList.toArray();
        return arg;
    }

}
